package com.demo.security.model;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.demo.security.utils.jackson.JacksonUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

/**
 * 自定义的返回Model
 * 
 * @author OL
 * @date 2016年4月10日-下午10:36:01
 */
@JsonInclude(value = Include.NON_NULL) // 序列化时忽略null字段
@JsonPropertyOrder({ "code", "success", "message", "data", "sys" }) // 按指定顺序序列化
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    // 这个值被设置为可以改变的, 但是全局统一
    public static int SUCC_CODE = 0;
    public static int FAIL_CODE = -1;

    /**
     * 返回码
     */
    private int code = SUCC_CODE;

    /**
     * 返回描述信息
     */
    private String message = null;

    /**
     * 查询时返回的结果集
     */
    private T data = null;

    /**
     * 系统信息:<br>
     * unique、runtime、ts等
     */
    private Map<String, Object> sys = new HashMap<String, Object>() {
        private static final long serialVersionUID = 1L;
        {
            put("ts", System.currentTimeMillis());
        }
    };

    /**
     * 未明确结果的返回
     * 
     * @param code
     * @param data
     * @return
     */
    public static <T> Result<T> fill(int code, String message) {
        Result<T> result = new Result<T>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    /**
     * 未明确结果的返回
     * 
     * @param code
     * @param data
     * @return
     */
    public static <T> Result<T> fill(int code, T data) {
        Result<T> result = new Result<T>();
        result.setCode(code);
        result.setData(data);
        return result;
    }

    /**
     * 未明确结果的返回
     * 
     * @param code
     * @param message
     * @param data
     * @return
     */
    public static <T> Result<T> fill(int code, String message, T data) {
        Result<T> result = new Result<T>();
        result.setCode(code);
        result.setMessage(message);
        result.setData(data);
        return result;
    }

    public static <T> Result<T> success() {
        return new Result<T>();
    }

    public static <T> Result<T> ok(String message) {
        Result<T> result = new Result<T>();
        result.setMessage(message);
        return result;
    }

    public static <T> Result<T> ok(T data) {
        Result<T> result = new Result<T>();
        result.setData(data);
        return result;
    }

    public static <T> Result<T> ok(String message, T data) {
        Result<T> result = new Result<T>();
        result.setMessage(message);
        result.setData(data);
        return result;
    }

    public static <T> Result<T> success(String message) {
        Result<T> result = new Result<T>();
        result.setMessage(message);
        return result;
    }

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<T>();
        result.setData(data);
        return result;
    }

    public static <T> Result<T> success(String message, T data) {
        Result<T> result = new Result<T>();
        result.setMessage(message);
        result.setData(data);
        return result;
    }

    public static <T> Result<T> failure(int code) {
        if (code == SUCC_CODE) {
            code = FAIL_CODE;
        }
        return new Result<T>(code);
    }

    public static <T> Result<T> failure(String message) {
        return new Result<T>(FAIL_CODE, message);
    }

    public static <T> Result<T> failure(String message, T data) {
        return new Result<T>(FAIL_CODE, message, data);
    }

    public static <T> Result<T> failure(int code, String message) {
        if (code == SUCC_CODE) {
            code = FAIL_CODE;
        }
        return new Result<T>(code, message);
    }

    public static <T> Result<T> failure(int code, T data) {
        if (code == SUCC_CODE) {
            code = FAIL_CODE;
        }
        Result<T> result = new Result<T>();
        result.setCode(code);
        result.setData(data);
        return result;
    }

    public static <T> Result<T> failure(int code, String message, T data) {
        if (code == SUCC_CODE) {
            code = FAIL_CODE;
        }
        return new Result<T>(code, message, data);
    }

    public static <T> Result<T> failureTemplate(int code, String message, Object... args) {
        message = MessageFormat.format(message, args);
        return new Result<T>(code, message);
    }

    public static <T> Result<T> failureTemplate(String message, Object... args) {
        message = MessageFormat.format(message, args);
        return new Result<T>(FAIL_CODE, message);
    }

    public Result() {
    }

    public Result(int code) {
        this.code = code;
    }

    public Result(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public Result(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public void refresh(int code) {
        this.code = code;
    }

    public void refresh(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public void refresh(T data) {
        this.data = data;
    }

    public void refresh(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public boolean isSuccess() {
        return SUCC_CODE == code;
    }

    public void setInfo(String key, Object value) {
        sys.put(key, value);
    }

    @SuppressWarnings("unchecked")
    public void addInfo(String key, Object value) {
        Object object = sys.get(key);
        if (object == null) {
            object = new ArrayList<Object>();
            sys.put(key, object);
        }
        if (object instanceof ArrayList) {
            ((ArrayList<Object>) object).add(value);
        }
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;

    }

    public void setMessage(String message) {
        this.message = message;

    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Map<String, Object> getSys() {
        return sys;
    }

    public void setSys(Map<String, Object> sys) {
        this.sys = sys;
    }

    @Override
    public String toString() {
        return JacksonUtils.toJsonString(this);
    }

    public static void main(String[] args) {
        System.out.println(new Result<Object>());
    }
}
